import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { signOut } from 'next-auth/react'

// Ensure BASE_URL is available in the environment
const BASE_URL = process.env.NEXT_PUBLIC_CLIENT_BASEURL || ''

// Define fetcher options type
export interface FetcherOptions extends AxiosRequestConfig {
  data?: Record<string, any>
  arg?: Record<string, any> // For SWRMutation compatibility
}

// Create and configure Axios instance
const axiosInstance: AxiosInstance = axios.create({
  baseURL: BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
})

// Add Axios interceptors for error handling, response validation, and token injection
axiosInstance.interceptors.request.use(
  (config) => config,
  (error) => Promise.reject(new Error(error.message))
)

axiosInstance.interceptors.response.use(
  async (response: AxiosResponse) => {
    const { code, message } = response.data
    if (code && code !== 'G_0000') {
      // Specific error codes handling
      if (['G_0404', 'G_0201', 'G_0202', 'APP_0004'].includes(code)) {
        await signOut()
        return Promise.reject(new Error('SESSION_EXPIRED', { cause: 'session_expired' }))
      }
      return Promise.reject(
        new AxiosError(
          message || 'Unknown error',
          code,
          response.config,
          response.request,
          response
        )
      )
    }
    return response
  },
  (error: AxiosError) => Promise.reject(error)
)

export const fetcher = async <T>(url: string, options: FetcherOptions = {}): Promise<T> => {
  const { method = 'GET', data = {}, headers = {}, ...config } = options
  if (method === 'GET' && Object.keys(data).length > 0) {
    const queryString = new URLSearchParams(data).toString()
    url += `?${queryString}`
  }
  const response = await axiosInstance({
    url,
    method,
    headers,
    // 不是GET的話則將 data 放入 body
    ...(method !== 'GET' && { data }),
    ...config,
  })
  return response.data.data as T
}

export default fetcher
